package ctrl;

import intf.AdHoc;

import javax.swing.JFrame;
import java.awt.BorderLayout;

import javax.swing.BorderFactory;
import javax.swing.DefaultListModel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import java.awt.FlowLayout;
import javax.swing.JLabel;
import javax.swing.JButton;
import java.awt.GridLayout;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;
import screen.ScreenView;
import web.Explorer;
import web.Cache;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.UnknownHostException;

import file.FileShare;

import netw.*;

public class Control {
	/**
	 * Set up empty modules
	 */

	Control ctrl = this;
	ScreenView svw = new ScreenView(ctrl);
	Overlay net = new Overlay(ctrl);
	FileShare fsr = new FileShare(ctrl);
	Users usr = new Users(ctrl);
	Explorer wb = new Explorer(ctrl);
	AdHoc ifmgt = new AdHoc(ctrl);
	Cache ch = new Cache(ctrl);

	// Accessible Interface elements
	public JFrame mainFrame;
	private JTextField overlayField;
	private JTextField nameField;
	private JTextField sendField;
	private JTextField cacheField;
	private JTextArea textArea;
	private JButton screenButton;
	private JButton createButton;
	private JButton connectButton;
	private JButton fileButton;
	private JList userList;
	private JList webList;
	private DefaultListModel userListModel;
	private DefaultListModel webListModel;

	// interface access methods
	public void print(final String text) {
		if (text.length() > 2)
			SwingUtilities.invokeLater(new Runnable() {
				public void run() {
					textArea.append(text + "\n");
				}
			});
	}

	public void println(final String text) {
		print((text));
	}

	public boolean debug = false; // TODO: change default

	public String screenBtnGetTxt() {
		return screenButton.getText();
	}

	public void screenBtnSetTxt(String s) {
		screenButton.setText(s);
	}

	// Module access functions

	public Overlay getNet() {
		return net;
	}

	public ScreenView getSvw() {
		return svw;
	}

	public FileShare getFs() {
		return fsr;
	}

	public Users getUsr() {
		return usr;
	}

	public Explorer getWeb() {
		return wb;
	}

	// User panel methodes

	public int[] selUsers() {
		return userList.getSelectedIndices();
	}

	public void addUser(String name) {
		userListModel.addElement(name);
	}

	public void remUser(int index) {
		userListModel.remove(index + 2);
	}

	// Site panel methods
	public void addSite(String name) {
		webListModel.addElement(name);
	}



	/**
	 * Create the application.
	 */
	public Control() {
		redirectSystemStreams();
		initialize();
	}

	// Build the frame content
	private void initialize() {
		mainFrame = new JFrame();
		mainFrame.setTitle("HyperCast Collaborator");
		mainFrame.setBounds(100, 100, 900, 500);
		mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		mainFrame.getContentPane().setLayout(new BorderLayout(0, 0));
		mainFrame.addWindowFocusListener(new WindowAdapter() { // set cursor to
																// sendField
																// automatically
																// upon focus
					public void windowGainedFocus(WindowEvent e) {
						sendField.requestFocusInWindow();
						textArea.setCaretPosition(textArea.getDocument()
								.getLength()); // for autoscroll
					}
				});

		// build middle panel
		JPanel outputPanel = new JPanel();
		mainFrame.getContentPane().add(outputPanel, BorderLayout.CENTER);
		outputPanel.setLayout(new BorderLayout(0, 0));

		JPanel sendPanel = new JPanel();
		outputPanel.add(sendPanel, BorderLayout.SOUTH);
		sendPanel.setLayout(new BorderLayout(0, 0));

		sendField = new JTextField();
		sendField.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				String text = sendField.getText();
				sendField.setText("");
				Chat.broadcast(text, ctrl);
			}
		});
		sendPanel.add(sendField);
		;

		textArea = new JTextArea();
		textArea.setEditable(false);
		textArea.setTabSize(25);
		textArea.setLineWrap(true);
		textArea.setCaretPosition(textArea.getDocument().getLength()); // for
																		// autoscroll
		JScrollPane pScroll = new JScrollPane(textArea,
				JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
				JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

		outputPanel.add(pScroll);

		// build left panel
		JPanel actionPanel = new JPanel();
		mainFrame.getContentPane().add(actionPanel, BorderLayout.WEST);
		actionPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5)); // top
																			// left
																			// bottom
																			// right
		actionPanel.setLayout(new BorderLayout(0, 0));

		JPanel joinPanel = new JPanel();
		actionPanel.add(joinPanel, BorderLayout.NORTH);
		joinPanel.setLayout(new GridLayout(0, 1, 0, 0));

		JPanel connectPanel = new JPanel();
		joinPanel.add(connectPanel);

		createButton = new JButton("Create");
		createButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				int results = ifmgt.create("HyperCast",
						"0123456789ABCDEF0123456789", createButton.getText());
				// SSID, 26 HEX password for 128bit WEP, button text
				if (results == 1) {
					createButton.setText("Disconnect");
					ctrl.println("System::Connected to ad-hoc network.");
					connectButton.setEnabled(false);
				} else if (results == 2) {
					createButton.setText("Create");
					ctrl.println("System::Disconnected from ad-hoc network.");
					connectButton.setEnabled(true);
				}
			}
		});
		connectPanel.add(createButton);

		connectButton = new JButton("Connect");
		connectButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				if (connectButton.getText() == "Connect") {
					ctrl.println("System::Connecting to ad-hoc network ...");
					ifmgt.connect("HyperCast", "0123456789ABCDEF0123456789");
					ctrl.println("System::Connected.");
					connectButton.setText("Disconnect");
					createButton.setEnabled(false);
				} else if (connectButton.getText() == "Disconnect") {
					ctrl.println("System::Disconnecting from ad-hoc network ...");
					ifmgt.disconnectNetwork();
					connectButton.setText("Connect");
					ctrl.println("System::Disconnected.");
					createButton.setEnabled(true);
				} else {
					System.out.println("$$ Error with Connect Button.");
				}
			}
		});
		connectPanel.add(connectButton);

		JPanel overlayPanel = new JPanel();
		FlowLayout flowLayout = (FlowLayout) overlayPanel.getLayout();
		flowLayout.setAlignment(FlowLayout.LEFT);
		joinPanel.add(overlayPanel);

		JLabel overlayLabel = new JLabel("Overlay");
		overlayPanel.add(overlayLabel);

		overlayField = new JTextField();
		overlayPanel.add(overlayField);
		overlayField.setColumns(10);

		JPanel name_Panel = new JPanel();
		joinPanel.add(name_Panel);
		FlowLayout fl_name_Panel = (FlowLayout) name_Panel.getLayout();
		fl_name_Panel.setAlignment(FlowLayout.LEFT);

		JLabel userLabel = new JLabel("Name   ");
		name_Panel.add(userLabel);

		nameField = new JTextField();
		nameField.setHorizontalAlignment(SwingConstants.LEFT);
		name_Panel.add(nameField);
		nameField.setColumns(10);

		JPanel panel_1 = new JPanel();
		joinPanel.add(panel_1);

		final JButton joinButton = new JButton("Join");
		
		nameField.addActionListener(new ActionListener() { //action listener for enter
			public void actionPerformed(ActionEvent arg0) {// same as below in the cacheField actionListener
				
				/*********Anything you edit here should be reflected below ********/
				if (!net.connected) {
					String ovl = overlayField.getText();
					if (ovl.equals("")) {
						ovl = "Default";
						overlayField.setText(ovl);
					}
					overlayField.setEditable(false);
					String name = nameField.getText();
					if (name.equals("")) {
						name = "User" + Integer.toString((int) (Math.random() * 100));
						nameField.setText(name);
					}
					nameField.setEditable(false);
					net.join(ovl);
					usr.setName(name);
					joinButton.setText("Leave");
					sendField.requestFocusInWindow();
				}
				/**************************************************************/
			}
		});
		
		joinButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				/*********Anything you edit here should be reflected above ********/
				if (!net.connected) {
					String ovl = overlayField.getText();
					if (ovl.equals("")) {
						ovl = "Default";
						overlayField.setText(ovl);
					}
					overlayField.setEditable(false);
					String name = nameField.getText();
					if (name.equals("")) {
						name = "User" + Integer.toString((int) (Math.random() * 100));
						nameField.setText(name);
					}
					nameField.setEditable(false);
					net.join(ovl);
					usr.setName(name);
					joinButton.setText("Leave");
					/**************************************************************/
				} else {
					net.leave();
					overlayField.setEditable(true);
					nameField.setEditable(true);
					joinButton.setText("Join");
					// Reset Share Screen Mode
					screenBtnSetTxt("Broadcast Screen");
					svw.resetMode();
				}
			}
		});

		panel_1.add(joinButton);

		JPanel cachePanel0 = new JPanel();
		joinPanel.add(cachePanel0);

		JPanel panel = new JPanel();
		joinPanel.add(panel);

		screenButton = new JButton("Broadcast Screen");
		screenButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				svw.action();
			}
		});
		panel.add(screenButton);

		JPanel panel_2 = new JPanel();
		joinPanel.add(panel_2);

		fileButton = new JButton("Send File");
		fileButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				fsr.action();
			}
		});
		panel_2.add(fileButton);

		JPanel spaceFiller = new JPanel();
		spaceFiller.setSize(30, 30);
		joinPanel.add(spaceFiller, BorderLayout.WEST);

		JPanel cachePanel = new JPanel();
		joinPanel.add(cachePanel);

		JLabel cacheLabel = new JLabel("http://");
		cachePanel.add(cacheLabel);

		cacheField = new JTextField();
		cacheField.setColumns(12);
		cacheField.addActionListener(new ActionListener() { //action listener for enter
			public void actionPerformed(ActionEvent arg0) {// same as below in the cacheField actionListener
				
				/*********Anything you edit here should be reflected below ********/
				String url = cacheField.getText();
				
				if (url != "") {
					if (!isInternetReachable(url)) {
						ctrl.println("System::This website is not reachable or not connected to the Internet.");
					}
					else {
						try {
							wb.cache(url);
						} catch (IOException e1) {
							System.out.println("@Control - IOException: " + e1.getMessage());
						}
					}
					sendField.requestFocusInWindow();
				}
				else {
					ctrl.println("System::Cannot leave field blank.");
				}
				/**************************************************************/
			}
		});
		cachePanel.add(cacheField);

		final JButton cacheButton = new JButton("Cache Site");
		cacheButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				
				/*********Anything you edit here should be reflected above ********/
				String url = cacheField.getText();
				
				if (url != "") {
					if (!isInternetReachable(url)) {
						ctrl.println("System::This website is not reachable!");
					}
					else {
						try {
							wb.cache(url);
						} catch (IOException e1) {
							System.out.println("@Control - IOException: " + e1.getMessage());
						}
					}
					sendField.requestFocusInWindow();
				}
				else {
					ctrl.println("System::Cannot leave field blank.");
				}
				/**************************************************************/
			}
		});

		JPanel panel_4 = new JPanel();
		joinPanel.add(panel_4);
		panel_4.add(cacheButton);
		
		// build right panel
		JPanel userPanel = new JPanel();
		userPanel.setLayout(new GridLayout(0, 1, 0, 0));
		userPanel.setBorder(BorderFactory.createEmptyBorder(10, 10, 0, 10)); // top
																				// left
																				// bottom
																				// right
		mainFrame.getContentPane().add(userPanel, BorderLayout.EAST);
		// userPanel.setLayout(new BorderLayout(0, 0));

		userListModel = new DefaultListModel();
		userListModel.addElement("User List:         ");
		userListModel.addElement("All");

		userList = new JList(userListModel);
		userList.setBackground(mainFrame.getBackground());
		userList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		userPanel.add(userList);

		JPanel webPanel = new JPanel();

		userPanel.add(webPanel);

		webListModel = new DefaultListModel();
		webListModel.addElement("Page List:           ");

		webList = new JList(webListModel);
		webList.setBackground(mainFrame.getBackground());
		webList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		MouseListener mouseListener = new MouseAdapter() {
			public void mouseClicked(MouseEvent e) {
				if (e.getClickCount() == 2) {
					wb.explore(webList.getSelectedIndices()[0] - 1);
				}
			}
		};
		webList.addMouseListener(mouseListener);
		webPanel.add(webList);
		wb.update();

		// Welcome message.
		// Instructions
		ctrl.println("Welcome. Select from the following options:");
		ctrl.println("   1. CREATE an Ad-hoc network and wait for users to join, or");
		ctrl.println("       CONNECT to the network.");
		ctrl.println("   2. Join with a Username.");
		ctrl.println("Leave the Overlay field blank (default) or pick an Overlay Name.");
		ctrl.println("    ");
		ctrl.println("You can then, cache a web site if you are connected to the Internet.");
		ctrl.println("Broadcast your screen.");
		ctrl.println("Send a file to a user or all users.");
		ctrl.println("Chat to a user or all users.");
		ctrl.println("Click on the Page List to refresh your list of web sites.");
		ctrl.println("    ");

		// Import Wireless Network Connection-HyperCast.xml
		String OS = System.getProperty("os.name").toLowerCase();
		if (OS.indexOf("windows") >= 0) {
			try {
				new intf.RunWindowsCmd("src\\script\\HyperCastConfig.bat");
			} catch (Exception e1) {
				System.out.println("@Control - Exception: " + e1.getMessage());
			}
		}
	}

	// Supporting methods

	private void redirectSystemStreams() {
		OutputStream out = new OutputStream() {
			public void write(int b) throws IOException {
				if (debug && !String.valueOf((char) b).contains("DT_Node"))
					print(String.valueOf((char) b));
			}

			public void write(byte[] b, int off, int len) throws IOException {
				if (debug && !new String(b, off, len).contains("DT_Node"))
					print(new String(b, off, len));
			}

			public void write(byte[] b) throws IOException {
				write(b, 0, b.length);
			}
		};

		System.setOut(new PrintStream(out, true));
		System.setErr(new PrintStream(out, true));
	}

	// checks for connection to the internet through dummy request
	public boolean isInternetReachable(String address) {
		try {
			// make a URL to a known source
			URL url = new URL("http://" + address);
			// open a connection to that source
			HttpURLConnection urlConnect = (HttpURLConnection) url
					.openConnection();
			// trying to retrieve data from the source. If there
			// is no connection, this line will fail
			/*Object objData = */ urlConnect.getContent();

		} catch (UnknownHostException e) {
			System.out.println("@Control - IOException: " + e.getMessage());
			return false;
		} catch (IOException e) {
			System.out.println("@Control - IOException: " + e.getMessage());
			return false;
		}
		return true;
	}
}
